package com.clw.classfile.constantpool;

import com.clw.classfile.BytesReader;
import com.clw.classfile.constantpool.info.ConstantClass;
import com.clw.classfile.constantpool.info.ConstantDouble;
import com.clw.classfile.constantpool.info.ConstantFieldRef;
import com.clw.classfile.constantpool.info.ConstantFloat;
import com.clw.classfile.constantpool.info.ConstantInfo;
import com.clw.classfile.constantpool.info.ConstantInteger;
import com.clw.classfile.constantpool.info.ConstantInterfaceMethodRef;
import com.clw.classfile.constantpool.info.ConstantInvokeDynamic;
import com.clw.classfile.constantpool.info.ConstantLong;
import com.clw.classfile.constantpool.info.ConstantMethodHandle;
import com.clw.classfile.constantpool.info.ConstantMethodRef;
import com.clw.classfile.constantpool.info.ConstantMethodType;
import com.clw.classfile.constantpool.info.ConstantNameAndType;
import com.clw.classfile.constantpool.info.ConstantString;
import com.clw.classfile.constantpool.info.ConstantUtf8;

/**
 * Created by chengliwei on 2018/11/9.
 */
public class ConstantPool {

    private ConstantInfo[] constantInfos;
    private BytesReader bytesReader;

    public ConstantPool(short length, BytesReader bytesReader) {
        constantInfos = new ConstantInfo[length];
        this.bytesReader = bytesReader;
        init();
    }

    private void set(int index, ConstantInfo cpInfo) {
        constantInfos[index] = cpInfo;
    }

    private int size() {
        return constantInfos.length;
    }

    private void init(){
        for (int i = 1; i < this.size(); i++) {
            byte tag = (byte) bytesReader.read();
            switch (tag) {
                case ConstantUtf8.TAG:
                    short length = bytesReader.readShort();
                    String utf8Content = bytesReader.readUTF8(length);
                    set(i, new ConstantUtf8(length, utf8Content));
                    break;
                case ConstantInteger.TAG:
                    set(i, new ConstantInteger(bytesReader.readInt()));
                    break;
                case ConstantFloat.TAG:
                    set(i, new ConstantFloat(bytesReader.readInt()));
                    break;
                case ConstantLong.TAG:
                    set(i++, new ConstantLong(bytesReader.readLong()));
                    break;
                case ConstantDouble.TAG:
                    set(i++, new ConstantDouble(bytesReader.readLong()));
                    break;
                case ConstantClass.TAG:
                    set(i, new ConstantClass(bytesReader.readShort()));
                    break;
                case ConstantString.TAG:
                    set(i, new ConstantString(bytesReader.readShort()));
                    break;
                case ConstantFieldRef.TAG:
                    set(i, new ConstantFieldRef(bytesReader.readShort(), bytesReader.readShort()));
                    break;
                case ConstantMethodRef.TAG:
                    set(i, new ConstantMethodRef(bytesReader.readShort(), bytesReader.readShort()));
                    break;
                case ConstantInterfaceMethodRef.TAG:
                    set(i, new ConstantInterfaceMethodRef(bytesReader.readShort(), bytesReader.readShort()));
                    break;
                case ConstantNameAndType.TAG:
                    set(i, new ConstantNameAndType(bytesReader.readShort(), bytesReader.readShort()));
                    break;
                case ConstantMethodHandle.TAG:
                    set(i, new ConstantMethodHandle((byte) bytesReader.read(),bytesReader.readShort()));
                    break;
                case ConstantMethodType.TAG:
                    set(i, new ConstantMethodType(bytesReader.readShort()));
                    break;
                case ConstantInvokeDynamic.TAG:
                    set(i, new ConstantInvokeDynamic(bytesReader.readShort(), bytesReader.readShort()));
                    break;
            }
        }
    }

    public String getUtf8(short attributeNameIndex) {
        return ((ConstantUtf8)(constantInfos[attributeNameIndex])).getBytes();
    }

    /*
    public static final int CONSTANT_Utf8 = 1;
    public static final int CONSTANT_Integer = 3;
    public static final int CONSTANT_Float = 4;
    public static final int CONSTANT_Long = 5;
    public static final int CONSTANT_Double = 6;
    public static final int CONSTANT_Class = 7;
    public static final int CONSTANT_String = 8;
    public static final int CONSTANT_Fieldref = 9;
    public static final int CONSTANT_Methodref = 10;
    public static final int CONSTANT_InterfaceMethodref = 11;
    public static final int CONSTANT_NameAndType = 12;
    public static final int CONSTANT_MethodHandle = 15;
    public static final int CONSTANT_MethodType = 16;
    public static final int CONSTANT_InvokeDynamic = 18;
    */
}
